<?php
// +----------------------------------------------------------------------
// | [KyPHP System] Copyright (c) 2020 http://www.kuryun.com/
// +----------------------------------------------------------------------
// | [KyPHP] 并不是自由软件,你可免费使用,未经许可不能去掉KyPHP相关版权
// +----------------------------------------------------------------------
// | Author: fudaoji <fdj@kuryun.cn>
// +----------------------------------------------------------------------

/**
 * Created by PhpStorm.
 * Script Name: Appstore.php
 * Create: 2020/5/17 下午5:10
 * Description: 应用商店
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace app\admin\controller;

use think\facade\Log;

class Appstore extends Base
{
    public $user = []; //开发者信息
    public $token = '';
    static public $baseUrl = 'https://kyphp.kuryun.com';
    static public $apis = [];
    private $client;

    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
        set_time_limit(0); //防止超时
        self::$apis = [
            'getApps'       => 'app/listPost',
            'getAppInfo'    => 'app/getPost',
            'getCates'      => 'app/getCatesPost',
            'getUser'       => 'user/getPost',
            'register'      => 'auth/registerPost',
            'login'         => 'auth/loginPost',
            'download'      => 'app/downloadPost',
            'listUpgradeApps' => 'app/listUpgradePost',
            'getAppUpgradePackage' => 'app/getUpgradePost'
        ];
        $this->setClient();
        $this->getUserInfo();
        $this->assign('official_href', self::$baseUrl);
    }

    /**
     * 获取个人信息
     * @return array|mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function getUserInfo(){
        if (!empty($token = session('kyphpToken'))) {
            $this->token = $token;
            $res = $this->doRequest(['uri' => self::$apis['getUser']]);
            if($res['code'] == 1){
                $this->user = $res['data']['user'];
                if($this->user){
                    session('kyphpToken', $token);
                }else{
                    session('kyphpToken', null);
                }
            }
        }
        $this->assign['user'] = $this->user;
        $this->assign['token'] = $this->token;
        return $this->user;
    }

    /**
     * 设置请求客户端
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function setClient(){
        $this->client = new \GuzzleHttp\Client(['base_uri' => self::$baseUrl . '/api/']);
    }

    /**
     * 请求官方接口
     * @param array $params
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    protected function doRequest($params = []){
        $data = empty($params['data']) ? [] : $params['data'];
        $request = new \GuzzleHttp\Psr7\Request('post', $params['uri'], ['token' => $this->token]);
        try {
            $res = $this->client->send($request, [
                'json' => $data
            ]);
            if($res->getStatusCode() == 200){
                return json_decode($res->getBody()->getContents(), true);
            }else{
                echo "请求失败";exit;
            }
        }catch (\Exception $e){
            Log::error($e->getMessage());
            echo "请求异常";exit;
        }
    }

    /**
     * 升级应用
     * @throws \think\db\exception\BindParamException
     * @throws \think\exception\PDOException
     * @return mixed|\think\response\Json
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function upgrade()
    {
        if (!$this->token)
            $this->error('请先登录应用商店', url('login'));

        if (request()->isPost()) {
            $post_data = input('post.');
            $addon_path = ADDON_PATH . $post_data['addon'] . DS;
            if (!file_exists($addon_path))
                $this->error($post_data['addon'] . '目录不存在');

            $addon = model('addons')->getOneByMap(['addon' => $post_data['addon']], true, true);

            $res = $this->doRequest(['uri' => self::$apis['getAppUpgradePackage'], 'data' => ['addon' => $post_data['addon'], 'version' => $addon['version']]]);
            if($res['code'] == 1){
                $upgrade = $res['data']['upgrade'];
            }else{
                $this->error($res['msg']);
            }

            $zip = new \ZipArchive;
            //备份
            $back_zip_name = env('runtime_path') . $post_data['addon'] . $addon['version'] . '-backup.zip';
            if (!$zip->open($back_zip_name, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) {
                $this->error('无法创建备份压缩包');
            }
            $this->addFileToZip($addon_path, $zip);
            $zip->close();

            $tem_file = env('runtime_path') . $post_data['addon'].$upgrade['version'].'-'.time() . '.tmp';
            $package = http_post($upgrade['upgrade_url'], []);
            file_put_contents($tem_file, $package);

            $res = $zip->open($tem_file);
            if ($res === TRUE) {
                $zip->extractTo(ADDON_PATH);
                $zip->close();
            } else {
                $this->error('解压失败，请检查是否有写入权限');
            }

            if (is_file($addon_path . 'upgrade.sql')) {
                execute_addon_upgrade_sql($addon_path . 'upgrade.sql');

                @unlink($addon_path . 'upgrade.sql');
            }
            @unlink($tem_file);
            model('addons')->updateOne(['id' => $addon['id'], 'version' => $upgrade['version']]);
            $this->success('恭喜您，升级成功');
        }

        $res = $this->doRequest(['uri' => self::$apis['listUpgradeApps']]);
        if($res['code'] == 1){
            $list = $res['data']['list'];
        }else{
            $this->error($res['msg']);
        }

        $data_list = [];
        if (!empty($list)) {
            foreach ($list as $v) {
                $addon = model('addons')->getOneByMap(['addon' => $v['name']], 'name,addon,version,author,logo', true);
                if(!empty($addon) && $v['version'] > $addon['version']){
                    $addon['new_version'] = $v['version'];
                    $addon['update_time'] = $v['update_time'];
                    $data_list[] = $addon;
                }
            }
        }

        return $this->show(['lists' => $data_list]);
    }

    /**
     * 将文件添加到压缩包中
     * @param $path
     * @param $zip
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function addFileToZip($path, \ZipArchive $zip)
    {
        $handler = opendir($path);
        while (($filename = readdir($handler)) !== false) {
            if ($filename != "." && $filename != "..") {
                if (is_dir($path . DS . $filename)) {
                    $this->addFileToZip($path . DS . $filename, $zip);
                } else {
                    $zip->addFile($path . DS . $filename);
                }
            }
        }
        @closedir($path);
    }

    /**
     * 下载APP
     * @return \think\response\Json
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function download()
    {
        $post_data = input('post.');
        $params = [
            'id' => $post_data['app_id']
        ];
        $res = $this->doRequest(['uri' => self::$apis['download'], 'data' => $params]);
        if($res['code'] == 1){
            $app = $res['data']['app'];
        }else{
            $this->error($res['msg']);
        }
        $app_install_path = ADDON_PATH . $app['name'] . DS;

        if (file_exists($app_install_path))
            $this->error($app['name'] . '目录已经存在或者您已经安装过【' . $app['title'] . '】，如果您要重新安装，请先卸载此应用');

        $app['package'] = http_post($app['package'], []);

        $tem_file = env('runtime_path') . $app['name'].$app['version'].'-'.time(). '.tmp';
        file_put_contents($tem_file, $app['package']);
        $zip = new \ZipArchive;
        $res = $zip->open($tem_file);
        if ($res === TRUE) {
            $zip->extractTo(ADDON_PATH);
            $zip->close();
            @unlink($tem_file); //删除临时压缩包
            $this->success('下载成功，正在跳转安装界面。。。', url('admin/app/index', ['type' => 'notinstall']));
        } else {
            $this->error('解压失败，请检查是否有写入权限');
        }
    }

    /**
     * 注册
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function register()
    {
        if($this->user){
            $this->redirect(url('index'));
        }
        if (request()->isPost()) {
            $data = input('post.');
            $params = [
                'username' => $data['username'],
                'password' => $data['password'],
                'repeat_password' => $data['repeat_password'],
                'name' => $data['name'],
                'domain' => $data['domain']
            ];
            $res = $this->doRequest(['uri' => self::$apis['register'], 'data' => $params]);
            if($res['code'] == 1){
                session('kyphpToken', $res['data']['token']);
                $this->success($res['msg']);
            }else{
                $this->error($res['msg']);
            }
        }
        return $this->show();
    }

    /**
     * 登录
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function login()
    {
        if($this->user){
            $this->redirect(url('index'));
        }
        if (request()->isPost()) {
            $data = input('post.');
            $params = [
                'username' => $data['username'],
                'password' => $data['password']
            ];
            $res = $this->doRequest(['uri' => self::$apis['login'], 'data' => $params]);
            if($res['code'] == 1){
                session('kyphpToken', $res['data']['token']);
                $this->success($res['msg']);
            }else{
                $this->error($res['msg']);
            }
        }
        return $this->show();
    }

    /**
     * 退出
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function logout()
    {
        session('kyphpToken', null);
        $this->redirect('index');
    }

    /**
     * 应用信息
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function appInfo()
    {
        $params = [
            'id' => input('id', 0, 'intval')
        ];
        $res = $this->doRequest(['uri' => self::$apis['getAppInfo'], 'data' => $params]);
        if($res['code'] == 1){
            $this->getAppCates();
            $this->assign['info'] = $res['data']['info'];
            $this->assign['upgrade_list'] = $res['data']['upgrade_list'];
        }else{
            $this->error($res['msg']);
        }
        return $this->show();
    }

    /**
     * 应用列表
     * @return mixed
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function index()
    {
        $type = input('type', 'all');
        $search_key = input('search_key', '');
        $cate = input('cate', '全部');
        $current_page = input('page', 1);
        $page_size = 12;
        $params = [
            'type' => $type,
            'cate' => $cate,
            'search_key' => input('search_key', ''),
            'current_page' => $current_page,
            'page_size' => $page_size
        ];
        $res = $this->doRequest(['uri' => self::$apis['getApps'], 'data' => $params]);
        if($res['code'] == 1){
            $this->getAppCates();
            $this->assign['total'] = $res['data']['total'];
            $this->assign['apps'] = $res['data']['list'];
            $this->assign['user_addon'] = $res['data']['user_addon'];
        }else{
            $this->error($res['msg']);
        }
        $this->assign['page_size'] = $page_size;
        $this->assign['search_key'] = $search_key;
        $this->assign['page'] = $current_page;
        $this->assign['type'] = $type;
        $this->assign['cate'] = $cate;
        return $this->show();
    }

    /**
     * 获取分类
     * Author: fudaoji<fdj@kuryun.cn>
     */
    private function getAppCates(){
        $res = $this->doRequest(['uri' => self::$apis['getCates']]);
        if($res['code'] == 1){
            $this->assign['cates'] = ['全部'] + $res['data']['cates'];
            $this->assign['types'] = ['all' => '全部'] + $res['data']['types'];
        }else{
            $this->error($res['msg']);
        }
    }
}